package com.yishe.controller.wxCore;

import com.google.common.collect.ImmutableMap;
import com.yishe.biz.mysql.WxUserBiz;
import com.yishe.biz.mysql.WxUserMemberInfoBiz;
import com.yishe.config.ObjectRestResponse;
import com.yishe.constant.WxConstants;
import com.yishe.entites.mysql.WxUser;
import com.yishe.entites.mysql.WxUserMemberInfo;
import com.yishe.entites.vo.UserVo;
import com.yishe.service.CoreService;
import com.yishe.utils.BeanCopyUtils;
import com.yishe.utils.ReturnModel;
import com.yishe.utils.XMLUtil;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.bean.oauth2.WxOAuth2AccessToken;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutNewsMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutTextMessage;
import me.chanjar.weixin.mp.bean.result.WxMpUser;
import me.chanjar.weixin.mp.config.WxMpConfigStorage;
import me.chanjar.weixin.mp.util.xml.XStreamTransformer;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * 微信核心功能
 */
@Controller
@RequestMapping("/wechat")
@Slf4j
public class WechatController extends GenericController {

    @Autowired
    private WxMpService wxMpService;
    @Autowired
    private WxMpConfigStorage configStorage;

    @Autowired
    protected CoreService coreService;

    @Resource
    private WxUserBiz wxUserBiz;
    @Resource
    private WxUserMemberInfoBiz wxUserMemberInfoBiz;

    @GetMapping(value = "/createJsapiSignature")
    @ResponseBody
    public ObjectRestResponse createJsapiSignature(String url) throws WxErrorException {
        ObjectRestResponse restResponse = new ObjectRestResponse();
        restResponse.setData(wxMpService.createJsapiSignature(url));
        return restResponse;
    }

    @GetMapping(value = "/getWxMpConfigStorage")
    @ResponseBody
    public ObjectRestResponse getWxMpConfigStorage() throws WxErrorException {
        ObjectRestResponse restResponse = new ObjectRestResponse();
        restResponse.setData(configStorage.getAccessToken());
        return restResponse;
    }


    @RequestMapping(value = "/test")
    public void index(HttpServletRequest request, HttpServletResponse response) throws IOException {
        response.setContentType("text/html;charset=utf-8");
        response.setStatus(HttpServletResponse.SC_OK);

        String signature = request.getParameter("signature");
        String nonce = request.getParameter("nonce");
        String timestamp = request.getParameter("timestamp");
        if (!this.wxMpService.checkSignature(timestamp, nonce, signature)) {
            // 消息签名不正确，说明不是公众平台发过来的消息
            response.getWriter().println("非法请求");
            return;
        }

        String echoStr = request.getParameter("echostr");
        if (StringUtils.isNotBlank(echoStr)) {
            // 说明是一个仅仅用来验证的请求，回显echostr
            String echoStrOut = String.copyValueOf(echoStr.toCharArray());
            response.getWriter().println(echoStrOut);
            return;
        }
    }


    /**
     * 微信公众号webservice主服务接口，提供与微信服务器的信息交互
     */
    @RequestMapping(value = "/core")
    public void wechatCore(HttpServletRequest request, HttpServletResponse response) throws Exception {
      response.setContentType("text/html;charset=utf-8");
        response.setStatus(HttpServletResponse.SC_OK);

        String signature = request.getParameter("signature");
        String nonce = request.getParameter("nonce");
        String timestamp = request.getParameter("timestamp");
        String event= request.getParameter("event");
        if (!this.wxMpService.checkSignature(timestamp, nonce, signature)) {
            // 消息签名不正确，说明不是公众平台发过来的消息
            response.getWriter().println("非法请求");
            return;
        }

        String echoStr = request.getParameter("echostr");
        if (StringUtils.isNotBlank(echoStr)) {
            // 说明是一个仅仅用来验证的请求，回显echostr
            String echoStrOut = String.copyValueOf(echoStr.toCharArray());
            response.getWriter().println(echoStrOut);
            return;
        }

        String encryptType = StringUtils.isBlank(request.getParameter("encrypt_type"))
            ? "raw"
            : request.getParameter("encrypt_type");
        if (filterEvent(request, response)) {
            return;
        }
        log.info("entryType:{}",encryptType);
        if ("raw".equals(encryptType)) {
            log.info("明文传输的消息");
            WxMpXmlMessage inMessage = WxMpXmlMessage.fromXml(request.getInputStream());
            WxMpXmlOutMessage outMessage = this.coreService.route(inMessage);
            if (outMessage == null ) {
                response.getWriter().write("欢迎关注本号！");
            } else {
                outMessage.setMsgType(WxConstants.MsgType.news.getCode());
                //测试
                WxMpXmlOutNewsMessage.Item item = new WxMpXmlOutNewsMessage.Item();
                item.setTitle("测试图文");
                item.setDescription("开发测试");
                item.setUrl("http://www.baidu.com");
                item.setPicUrl("https://gimg2.baidu.com/image_search/src=http%3A%2F%2Flmg.jj20.com%2Fup%2Fallimg%2F811%2F040915120S0%2F150409120S0-5-1200.jpg&refer=http%3A%2F%2Flmg.jj20.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1664029104&t=dca6da174995b6f6f8412405ffac1b0a");
                WxMpXmlOutNewsMessage newsMessage = outMessage.NEWS().addArticle(item).build();
                newsMessage.setArticleCount(1);
                newsMessage.setFromUserName(outMessage.getFromUserName());
                newsMessage.setToUserName(outMessage.getToUserName());
                log.info("return xml \r\n:{}",newsMessage.toXml());
                response.getWriter().write(newsMessage.toXml());
            }
            return;
        }

        if ("aes".equals(encryptType)) {
            log.info("是aes加密的消息");
            // 是aes加密的消息
            String msgSignature = request.getParameter("msg_signature");
            WxMpXmlMessage inMessage = WxMpXmlMessage.fromEncryptedXml(
                request.getInputStream(), this.configStorage, timestamp, nonce,
                msgSignature);
            log.debug("\n消息解密后内容为：\n{} ", inMessage.toString());
            WxMpXmlOutMessage outMessage = this.coreService.route(inMessage);
            if (outMessage == null) {
                response.getWriter().write("");
            } else {
                response.getWriter().write(outMessage.toEncryptedXml(this.configStorage));
            }

            return;
        }

        response.getWriter().println("不可识别的加密类型");
    }

    /**
     * 通过openid获得基本用户信息
     * 详情请见: http://mp.weixin.qq.com/wiki/14/bb5031008f1494a59c6f71fa0f319c66.html
     *
     * @param openid openid
     * @param lang   zh_CN, zh_TW, en
     */
    @RequestMapping(value = "/getUserInfo")
    @ResponseBody
    public WxMpUser getUserInfo(HttpServletResponse response, @RequestParam(value = "openid") String openid,
                                @RequestParam(value = "lang") String lang) {
        ReturnModel returnModel = new ReturnModel();
        WxMpUser wxMpUser = null;
        try {
            wxMpUser = this.wxMpService.getUserService().userInfo(openid, lang);
            returnModel.setResult(true);
            returnModel.setDatum(wxMpUser);
            renderString(response, returnModel);
        } catch (WxErrorException e) {
            returnModel.setResult(false);
            returnModel.setReason(e.getError().toString());
            renderString(response, returnModel);
            log.error(e.getError().toString());
        }
        return wxMpUser;
    }

    /**
     * 通过code获得基本用户信息,并更新對應数据库中的用户信息
     * 详情请见: http://mp.weixin.qq.com/wiki/14/bb5031008f1494a59c6f71fa0f319c66.html
     *
     * @param params{ code,account}
     */
    @PostMapping(value = "/getOauth2UserInfo")
    @ResponseBody
    public ObjectRestResponse getOauth2UserInfo(HttpServletResponse response, @RequestBody Map<String, String> params) {
        WxOAuth2AccessToken accessToken;
        UserVo userVo = new UserVo();
        ObjectRestResponse restResponse = new ObjectRestResponse();
        try {
            String code = params.get("code");
            String account = params.get("account");
            accessToken = this.wxMpService.getOAuth2Service().getAccessToken(code);
            wxMpService.getOAuth2Service().refreshAccessToken(accessToken.getRefreshToken());
            WxMpUser wxMpUser = this.wxMpService.getUserService().userInfo(accessToken.getOpenId());
            //获取后完善用户表中的其他数据
            WxUser wxUser = new WxUser();
            wxUser.setWxAccount(account);
            wxUser = wxUserBiz.selectOne(wxUser);
            WxUserMemberInfo wxUserMemberInfo = new WxUserMemberInfo();
            wxUserMemberInfo.setWxAccount(account);
            wxUserMemberInfo = wxUserMemberInfoBiz.selectOne(wxUserMemberInfo);
            //将openid更新到用户信息和用户会员信息表中
            if (StringUtils.isBlank(wxUser.getOpenid())) {
                BeanCopyUtils.copy(wxUser, wxMpUser);
                wxUser.setSex(String.valueOf(wxMpUser.getSex()));
                wxUser.setOpenid(wxMpUser.getOpenId());
                wxUserBiz.updateById(wxUser);
            }
            if (StringUtils.isBlank(wxUserMemberInfo.getOpenid())) {
                wxUserMemberInfoBiz.updateOpenIdById(ImmutableMap.of("openid",wxMpUser.getOpenId(),"id",wxUserMemberInfo.getId()));
            }
            Map<String, Object> data = new HashMap<>(1);
            data.put("userInfo", userVo);
            userVo.setWxUser(wxUser);
            restResponse.setData(data);
        } catch (WxErrorException e) {
            restResponse.setErrorMsg(e.getMessage());
            log.error(e.getError().toString());
        }
        return restResponse;
    }


    /**
     * 拦截微信事件
     *
     * @param request
     * @return
     */
    private boolean filterEvent(HttpServletRequest request, HttpServletResponse response) throws Exception {
        boolean isFilter = false;
        //拦截事件
        Map<String, String> params = XMLUtil.parseRequestXmlToMap(request);
        if (!params.isEmpty()) {
            String msgType = params.get("MsgType");
            String event = params.get("Event")==null?"":params.get("Event").toLowerCase();
            //是一个事件
            if (msgType.equals(WxConstants.MsgType.event.getCode())) {
                //订阅
                if (event.equals(WxConstants.MsgType.subscribe.getCode())) {
                    WxMpXmlOutTextMessage wxMpXmlOutTextMessage = new WxMpXmlOutTextMessage();
                    wxMpXmlOutTextMessage.setToUserName(params.get("FromUserName"));
                    wxMpXmlOutTextMessage.setContent("感谢订阅！");
                    wxMpXmlOutTextMessage.setCreateTime(System.currentTimeMillis());
                    wxMpXmlOutTextMessage.setFromUserName(params.get("ToUserName"));
                    response.getWriter().write(XStreamTransformer.toXml(WxMpXmlOutTextMessage.class, wxMpXmlOutTextMessage));
                    isFilter = true;
                } else if (event.equals(WxConstants.MsgType.unsubscribe.getCode())) {
                    log.info("取消订阅了");
                    isFilter = true;
                } else if (event.equals(WxConstants.MsgType.location.getCode())) {
                    log.info("获取定位权限");
                    isFilter = true;
                }
            }
        }
        return isFilter;
    }


}
